home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-05-18 | 121.2 KB | 3,209 lines |
- ______ ________ ______
- / | \ | /
- ( | \ | (
- \______ | \ | \______
- \ | ) | \
- ) | / | )
- ________/ _|_______/ |________ ________/
-
- T h e S t r a y l i g h t D y n a m i c L i n k i n g S y s t e m
-
-
- Straylight
-
- 16 Portland Street, Royal Leamington Spa,
- Warwickshire, CV32 5HE
-
- Telephone and facsimile: 01926 452639
- Email: strylght@strylght.demon.co.uk
-
- _____________________________________________________________________________
-
-
- Some notes on this document
-
-
- This text file should contain the complete text of the SDLS manual.
- It has been generated by Impression, and formatted by hand.
- Therefore, there may be come accidental omissions, and the formatting
- may differ from the original document.
-
- This text file should therefore be viewed as a `convenience'. The
- definitive version of the documentation is the Impression Publisher
- document.
-
- In addition, it is not possible to include all of the figures and
- tables in a text form. These are supplied in Draw and ArtWorks
- format. To view the ArtWorks files, use Computer Concepts' AWViewer
- application, available on hensa, and from many other sources.
-
- Note that listings are not formatted, and may extend past the end
- of a line. This is so that you can extract the listings and use
- them in your own code directly.
-
- _____________________________________________________________________________
-
-
- © 1995 Straylight. All rights reserved.
-
- This documentation refers to the Straylight Dynamic Linking System
- version 1.00.
-
- There is no warranty for the program, to the extent permitted by
- applicable law. Except when otherwise stated in writing the
- copyright holders and/or other parties provide the program ‘as is’
- without warranty of any kind, either expressed or implied, including,
- but not limited to, the implied warranties of merchantability and
- fitness for a particular purpose. The entire risk as to the quality
- and performance of the program is with you. Should the program prove
- defective, you assume the cost of all necessary servicing, repair or
- correction.
-
- The product described in this documentation is the subject of
- continual development and, while all efforts are taken to ensure
- that the information given is correct, Straylight cannot accept any
- liability for loss or damage resulting from the use or misuse of this
- product.
-
- Trademarks
-
- Acorn, Archimedes and RISC PC are trademarks of Acorn Computers Ltd.
- ARM is a trademark of Advanced RISC Machines Ltd.
- All other trademarks acknowledged.
-
- _____________________________________________________________________________
-
-
- Introduction
-
-
- An introduction to dynamic linking
-
- Many current RISC OS applications use common libraries such as
- RISC_OSLib or DeskLib. Such libraries are usually quite large, and
- currently each application using the library contains its own copy of
- the library code. This is wasteful of both disk space and, much
- more importantly, memory space. Figure 1.1 shows this
- diagrammatically.
-
- Figure 1.1: Applications using common libraries
-
- This document describes a method for libraries to be held as separate
- files, allowing multiple applications to use a single copy of the
- library held in memory. In order for this system to work, an
- application must be able to find the routines it requires at
- run-time. This process is called ‘dynamic linking’, by analogy with
- normal ‘static’ linking. Figure 1.2 shows this improvement applied
- to the situation shown in Figure 1.1.
-
- Figure 1.2: Applications using a shared library
-
- With dynamic linking, our view of what constitutes an application
- must change. We must now consider an application to consist of:
-
- • One main program, which contains the main application code.
- This main program will normally be contained within an absolute
- image, although it is also possible for it to be kept in a
- RISC OS relocatable module.
-
- • Any number of Dynamic Link Libraries, which may be shared with
- other applications.
-
- For the Straylight Dynamic Linking System (SDLS) to work, a small
- module called the DLLManager is provided.
-
-
- Languages supported by the system
-
- The Straylight Dynamic Linking System is designed to support compiled
- languages which conform to the APCS-R calling standard. This
- includes most C compilers available for Acorn RISC machines, and
- Acorn’s DDE Pascal implementation. It also allows creation of DLLs
- written in assembler, using any procedure call standard, although in
- this case much more work is required to implement DLLs.
-
-
- Who can use SDLS?
-
- Straylight have decided to make SDLS ‘freeware’. It remains at all
- times Copyright © 1995 Straylight; however:
-
- • Applications using shared or extension DLLs may be distributed
- with the DLLManager module and !DLLs resource as required.
-
- • Development kits for shared DLLs may be distributed with parts of
- this package as required.
-
- The above applies to all software products whether or not they are
- commercial. No charge may be made for any part of SDLS specifically,
- and none of the code or documentation may be altered in any way. You
- may use parts of this documentation within your own manuals for
- shared libraries or applications if you wish.
-
- All products distributed with SDLS or any parts thereof must state in
- the main documentation such parts are copyright © 1995 Straylight.
-
-
- About this manual
-
- This document divided into two parts: a user guide and a reference
- manual. The user guide gives an overview of the main concepts
- required to use SDLS. Further details may be found in the reference
- manual.
-
- The Straylight Dynamic Linking System can be used at two different
- levels: the development of client applications that use existing
- DLLs, and the creation of new Dynamic Link Libraries. Both of these
- processes are dealt with individually in the user guide.
-
- It isn’t necessary to learn how to create your own DLLs if you’re
- only going to be using existing libraries, although it may give some
- additional insight into how the system works. It is necessary to be
- familiar with both sections if you will be developing DLLs yourself.
-
-
- Terminology
-
- The following terms are used throughout this document:
-
- Dynamic Link Library A collection of routines, usually with a
- common purpose, which may be shared by any
- number of applications running at the same
- time. ‘Dynamic Link Library’ is often
- abbreviated as ‘DLL’.
-
- Client application An application which makes use of a Dynamic
- Link Library.
-
- External procedure call A call from a client application to a DLL,
- from a DLL to a client application, or from
- one DLL to another.
-
-
- Package contents
-
- The Straylight Dynamic Linking System consists of several parts:
-
- • A !DLLs shared resource, which will contain Dynamic Link
- Libraries, and allow applications to locate them when required.
-
- • The !DLLMerge application, which allows users to update their
- !DLLs resource as part of the installation of a new application.
-
- • A DLLLib library, which provides support for the dynamic linking
- system.
-
- • The cdll tool, which generates AOF (Acorn Object Format) files
- useful in constructing DLLs and client applications.
-
- • A Tutorials directory, which contains example programs used to
- demonstrate the use of the system.
-
- _____________________________________________________________________________
-
-
- P A R T I : U S E R ' S G U I D E
-
- _____________________________________________________________________________
-
-
- !DLLs and !DLLMerge
-
-
- The Straylight Dynamic Linking System provides a shared resource
- called !DLLs. It collects together DLLs and allows client
- applications to easily locate the ones that they require. This is
- very similar to the way the standard !System resource allows
- applications to locate the relocatable modules that they need.
-
- It is normal to keep the !DLLs and !System resources together. If
- you have a Risc PC, you will find the !System resource in the
- directory $.!Boot.Resources.
-
- The !DLLs resource sets up two system variables:
-
- • DLL$Dir is the full path name of the !DLLs resource.
-
- • DLL$Path is a path variable allowing access to all currently
- available shared DLLs.
-
- Inside the !DLLs resource folder are the following files:
-
- • !Boot and !Run − set up the system variables properly.
-
- • DLLManager − the DLLManager module. It is placed here so that
- client applications can find it easily.
-
- • A few small utility programs which are used to set up the system
- variables.
-
- • A number of subdirectories containing DLLs.
-
- The DLLMerge application is aimed at simplifying the process of
- installing applications which require DLLs. It works in a
- more-or-less identical way to Acorn’s SysMerge utility. To use it,
- double click on the !DLLMerge icon, and drag your master DLLs
- resource folder to the main window, followed by the DLLs folder on
- the distribution disk. DLLMerge then updates the master DLLs
- resource from the copy on the distribution disk, and rescans the
- resource folder to update the system variables.
-
- _____________________________________________________________________________
-
-
- Using existing DLLs
-
-
- Introduction
-
- This chapter will describe how to write client applications which use
- one or more DLLs in the most common way. If a library has unusual
- requirements, they will be specified in that library’s documentation.
- In general, using a Dynamic Link Library is very similar to using the
- traditional statically linked kind − all you will need to do is link
- with some different files.
-
- A DLL will always come in two parts: the actual library code, which
- is held in the !DLLs resource, and a small ‘stub’, which you link
- into your application. If you’re using more than one DLL, you will
- usually just link with the stubs for each one. The stub contains
- information which enables the DLLManager module to load and prepare
- the DLL for use.
-
-
- Ensuring library versions
-
- Your application will need to ensure that sufficiently recent
- versions of all the libraries that it needs are available before it
- starts up. You can do this in the application’s !Run file using the
- *command *DLLEnsure as follows:
-
- DLLEnsure <library name> <version>
-
- You will be told the library’s name and version number in the
- library’s documentation.
-
-
- Client applications written in C
-
- If your application makes use of the Shared C Library, then your link
- step will need to be modified slightly. In order to correctly load
- the libraries your application needs, you will need to link with the
- DLLLib library supplied with the SDLS distribution. Also, instead
- of linking with the standard ‘stubs’, you will need to link with an
- alternative Shared C Library stub, as follows:
-
- • For a normal application, use ‘astubs’.
-
- • For a relocatable module, use ‘mstubs’.
-
- These replacement stubs are compatible with those supplied with Acorn
- C Releases 3 and 4. However, the stubs supplied with C Release 5
- contain the new routines _swi and _swix. If your application makes
- use of these routines, you have two choices: either you can use the
- stubs described above, and also link with the file ‘swiv’ provided
- in the distribution, or you can use the asstubs or msstubs versions
- (note the additional ‘s’). The latter alternative will use the
- routines contained in the Shared C Library, which saves memory, but
- will prevent your program working under RISC OS 2. Also, the
- versions of these routines in the Shared C Library contain a small
- bug which is not present in the swiv program in this distribution.
- For these reasons, we recommend that you do not use the versions of
- these routines in the Shared C Library.
-
- We suggest that you add the DLLLib directory to your standard library
- path (which will normally be C$Path). This will allow you to specify
- the object and header files within the directory easily from all of
- your project directories. In the examples, we will assume that you
- have done this.
-
-
- A brief tutorial
-
- In the directory Tutorial.ClicntEx, there is an example of a very
- simple client application written in C. You don’t actually need a C
- compiler, since we’ve already compiled the source code for the
- client. You will however need a linker; either Acorn’s link or the
- freely available drlink is recommended for this purpose. This
- section will show you how to create the actual application image.
-
- We have not supplied a makefile for this example, because we feel
- that it will be more instructive to perform the operation manually.
-
- The example client requires the DLLExample DLL which is already in
- the !DLLs resource. The header file h.dllExample describes the
- functions this very simple library offers. The DLL’s stub is
- contained in o.dllExample.
-
- To build the client application, all you need to do is:
-
- 1. Make Tutorial.ClientEx your current directory.
-
- 2. Perform the following command:
-
- link o.clientEx o.dllExample c:o.dllLib c:o.astubs -o ClientEx
-
- (We’ve used Acorn’s link here, although you can use drlink in exactly
- the same way.)
-
- The application is now complete. If you just run the command
- ClientEx, a greeting and the current time and date should be printed
- on your screen.
-
- Note that if you want to compile the source code (clientEx.c), you do
- this in the usual way.
-
- Complications
-
- Usually, creating your client application is as simple as explained
- above. However, a lot of this simplicity is dependent on the DLLs
- you are using, and you should watch out for some pitfalls. In order
- for the DLLManager to keep track of which application is currently
- calling DLL routines, it makes use of the time at which the
- application was started. Unfortunately, some operating system calls
- alter this time, and so you must ensure that you restore it
- immediately afterwards. Essentially, any operating system call
- which allows another application to run will alter the start time;
- these calls are: Wimp_Poll, Wimp_PollIdle, OS_CLI and Wimp_StartTask
- (which calls OS_CLI)¹. There are DLLManager calls which allow you
- to save and restore this time value, and you can use these to
- ‘protect’ the offending operating system routines, as follows:
-
- • In C (using the DLLLib functions):
-
- {
- int save;
- dll_saveHandle(&save);
- /* Do operation that needs 'protection' */
- dll_restoreHandle(&save);
- }
-
- • In assembler:
-
- SWI DLL_SaveHandle ;Get application handle
- STMFD R13!,{R0} ;Save it on the stack
- ; Do operation that needs 'protection'
- LDMFD R13!,{R0} ;Get application handle back
- SWI DLL_RestoreHandle ;Set it as the current one
-
- DLLlib already includes functions for handling OS_CLI and
- Wimp_StartTask ‘safely’. A good WIMP library will provide a way of
- calling Wimp_Poll and Wimp_PollIdle.
-
- The other problem, which only applies if your program is written in C
- or a similar language, is that the DLLManager needs to be able to
- keep track of which part of an application is currently executing.
- Normally, this will happen automatically. Problems only occur when
- your program does not follow normal function call and return
- discipline. This will usually happen as a result of a call to the
- standard C longjmp function. The problems occus because the
- DLLManager needs to maintain a stack containing information about
- external procedure calls, and a longjmp call causes the DLLManager’s
- stack pointer to become out of sync. The solution is to remember
- the stack pointer when you call setjmp and restore it again when
- setjmp returns, as follows:
-
- {
- int stackptr;
- jmp_buf j;
-
- dll_readStackPtr(&stackptr);
- if (setjmp(j))
- {
-
- /* --- Someone longjmped here --- */
-
- dll_setStackPtr(stackptr);
- /* Other handling */
- }
- }
-
- Module clients written in C
-
- Special care must be taken if your client application is actually a
- relocatable module. If your module passes function pointers to a
- DLL, then you should read the sections on The cdll tool and
- Complications in the next chapter before reading any further.
-
- Due to the way the DLLManager works, a module client must contain
- entry veneers for each function which may be called from a DLL
- through a function pointer. These are created by cdll − you must
- create a definition file containing only the ‘extEntry’ and
- ‘objects’ sections. You can generate an object file containing the
- entry veneers for the functions named in the ‘extEntry’ section by
- using the command:
-
- cdll -def <defn file> -ext <output file>
-
- Note that the entry veneer for a function foobar will be
- _extEntry_foobar.
-
- _____________________________________________________________________________
-
-
- Creating Dynamic Link Libraries
-
-
- Introduction
-
- This part of the manual will explain how you can write your own
- Dynamic Link Libraries. It is expected that you have already read
- the chapter Using existing DLLs.
-
- Creating DLLs can be a considerably more complex task than writing
- client applications − this doesn’t mean that all libraries will be
- hard to write, but the relative ease of writing clients is mainly
- due to the effort put in by the library developers.
-
- Whether you are writing an entirely new Dynamic Link Library, or
- converting an existing static library into a DLL, it is vital that
- you have a reasonable understanding of the concepts introduced here.
- Such familiarity will make your task as a DLL developer much
- simpler.
-
-
- Structure of a DLL
-
- Conceptually, a Dynamic Link Library consists of two parts: the code
- part, which contains all the routines that client applications will
- use, and the header, which contains information used by the
- DLLManager module. Each routine that a DLL exports to its clients has
- an entry point − this is simply the start address of the routine in
- memory. In order to use a routine, the client application must find
- its entry point; we will discuss how this is done below.
-
- The code part of a DLL is usually built from a number of AOF object
- files or statically linked libraries. These are generated from your
- library’s source code in the same way as for a statically linked
- library. Naming of DLLs and entry points
-
- The DLLManager keeps track of Dynamic Link Libraries by use of their
- names. For this reason, each DLL must have a unique name. If you
- are planning to release a DLL, you should read the chapter
- Registering names. DLL names may be at most 10 characters long, and
- must be the same as its leafname.
-
- Each entry point must also be given a name. Entry point names only
- have to be unique within a particular DLL. However, you should be
- aware that the linker will not allow multiple definitions of
- identifiers. This rarely occurs in practice with well-chosen names
- − we recommend that you group routines with a common purpose by
- giving them a suitable common prefix. For example, in a library
- offering WIMP services, all the routines concerned with dialogue box
- management might begin with the prefix ‘dbox_’. Since a client is
- unlikely to use more than one such library, this naming strategy
- should not cause too many problems.
-
-
- ‘Foreverness’ and version control
-
- One of the main difficulties in designing a Dynamic Link Library is
- version control. A version of a DLL must try to remain compatible
- with clients which were written for an earlier version of the
- library. This means that the routines provided by your library must
- keep the same external interfaces, or ones which are compatible with
- earlier releases. This concept is termed ‘foreverness’.
-
- A full discussion of foreverness is beyond the scope of this
- document. However, when designing a DLL you should attempt to
- ensure that you can easily extend your interfaces in a compatible
- way, for example by making use of reserved fields and flags.
- RISC OS itself contains many good examples of this sort of design.
-
- The DLLManager goes some way to help you with the problems of version
- control. You must include a version number in the header of a DLL.
- This is checked against the version number requested by the client.
- An error is reported if there is no sufficiently recent version of
- your library available. A complete discussion of version handling is
- given in the reference part of this document.
-
-
- The cdll tool
-
- The DLL header and stubs files have a fairly complex format, and
- building these by hand is difficult and prone to errors. The cdll
- tool is a small program which will generate these and other dynamic
- linking- related data structures from simple textual descriptions. A
- full descrip tion of cdll is given in the chapter The cdll tool in
- the reference section. Here, we shall only discuss the parts
- relevant to the creation of Dynamic Link Libraries.
-
- Definition files
-
- You describe your DLL to cdll by means of a definition file, which
- contains all the information needed to create the DLL’s header and
- stub. An annotated example of a definition file for a simple DLL is
- shown in figure 4.1.
-
- If you are converting an existing statically linked library into a
- DLL, then the creation of a definition file by hand would be very
- time-consuming.
-
- To help solve this problem, cdll can create a skeleton definition
- file based on a number of given object files and libraries. You
- will need to modify the resulting file by hand before you can use
- it, although cdll will have done the bulk of the work for you. To
- do this, use the command
-
- cdll -def <output file> -obj <object/library files>
-
- If you are creating a Dynamic Link Library from scratch, or you have
- a definition file prepared using the above method, you will need to
- maintain the file by hand as you add new routines to your library.
- This is unlikely to be difficult.
-
- Creating DLL headers and stubs
-
- Once you have a definition file, you can create the DLL’s header and
- stubs as AOF (object) files using the command:
-
- cdll -def <defn file> -stub <stub name> -hdr <header name>
-
- The stub is ready for inclusion in client applications, as described
- in the previous chapter. The header can be used to create the
- finished Dynamic Link Library as explained below.
-
- Linking
-
- Once you have the object files for your DLL’s code and header parts,
- you can link them together to form the finished DLL:
-
- link -rmf <object files> -o <dll filename>
-
- It is important to notice that the linker’s ‘-rmf’ option is used −
- this will automatically create the code necessary to relocate the
- DLL when it is loaded. The freely available drlink program also has
- this option. The DLL file created by link using the above command has
- its filetype set to be a relocatable module. You will probably want
- to change this to be Data (type &FFD).
-
- Writing DLLs in C
-
- There are some special considerations you must bear in mind when
- writing a DLL in C or a similar language. The compiler options
- described here are applicable to the Acorn C and Pascal compilers.
- Other compilers may include equivalent features − check your
- compiler’s documentation for details.
-
- Compiling
-
- When you compile code for use in a Dynamic Link Library, you must use
- the compiler’s ‘-zM’ option, which requests the compiler to create
- code suitable for a relocatable module. Code compiled in this way
- has properties which make it possible for it be used in DLLs. If
- your compiler does not support an equivalent option, you will not be
- able to create DLLs with it.
-
- The SDLS package contains some replacement C library header files
- (ctype.h, errno.h, math.h and stdio.h) as part of the DLLLib, and you
- must ensure that these are included by your source files, instead of
- the standard ones. To activate the modifications made to these
- header files, you must define the macro _DLL (e.g. using the
- compiler option ’-d_DLL‘) − this must only be done when compiling
- code for a DLL; do not define this symbol when creating client
- applications. Assuming that the replacement header files are
- contained within the directory c:dlllib.h, you can ensure that they
- are included correctly by using the option ’Jc:dlllib.,:mem‘. This
- overrides the default search mechanism, which will find copies of
- the header files embedded in the compiler, and instead locates the
- SDLS versions first. If your compiler does not support this type of
- operation, you must use explicit paths in your source code (e.g.
- #include "c:dlllib.h.stdio").
-
- As an example, to compile the file c.hellow, use the command
-
- cc -d_DLL -Jc:dlllib.,:mem -zM -c hellow.c -o hellow.o
-
- The compiler commands can become very complicated − we therefore
- recommend that you use a makefile to manage creation of DLLs.
-
- Linking
-
- When you are linking your object files to create the final Dynamic
- Link Library, you must also link with the DLLLib library and the
- dstubs Shared C Library stubs. For example
-
- link -rmf <object files> c:dlllib.o.dlllib c:dlllib.o.dstubs
- -o <dll filename>
-
- Note that the dstubs do not include the new Shared C Library entry
- points _swi and _swix − if you require these, you should link with
- the supplied swiv object file as described in the previous chapter.
-
- Debugging
-
- Unfortunately, it is not possible to include debugging information in
- a DLL. If you wish to debug your library, it is wise to allow both
- a statically and dynamically linked version to be built from the
- same source code. You can use the preprocessor macro _DLL described
- above to conditionally compile the appropriate code for both
- versions.
-
- Complications
-
- All the complications described in the previous chapter, regarding
- Wimp_Poll etc. and longjmp also apply to DLLs. However, there is a
- further complication if you use function pointers.
-
- The DLLManager must perform some setting-up operations whenever one
- of your DLL’s entry points is called. This happens automatically
- most of the time. However, you must be careful when returning
- pointers to functions contained within your library to the client
- application. A normal call to one of your routines is actually
- routed through a small piece of code called an entry veneer. This
- allows the DLLManager to perform its setting up before it passes
- control to the actual routine. If the client application were to
- call one of your routines directly through a function pointer, the
- DLLManager would not be able to set up the environment correctly for
- the routine, and your program would fail. The solution is to ensure
- that you always return the address of the routine’s entry veneer,
- rather than its actual address.
-
- Each entry veneer is given a name based on its routine’s name − for
- example, the entry veneer for the routine dbox_create would be called
- _dllEntry_dbox_create. If you want to set up a function pointer with
- the address of a routine which may be returned to the client
- application, you must instead use the name of the entry veneer.
-
- Note that if a function pointer will not be used outside of your DLL,
- you need not use the address of the veneer. However, no harm will
- be done if you do.
-
- You may have routines which you do not want to export to the client
- application by name, but you may want to be able to return function
- pointers to them. You can do this by naming them in your cdll
- definition file in a section labelled extEntry. This section is
- otherwise the same as the exports section already discussed.
-
- To assist in the management of source code being used in both
- statically and dynamically linked libraries, the DLLLib library
- contains a header file dll.h which defines the following macros:
-
- _dll_static When compiling a statically linked library, this
- macro expands to ‘static’. When compiling a DLL, it
- does nothing. This is useful if you are returning a
- function pointer to a function, but do not want it
- visible to the client.
-
- _dllEntry(x) When compiling a statically linked library, this
- macro expands to just ‘x‘. When compiling a DLL, it
- expands to ‘_dllEntry_x’.
-
- Writing DLLs in assembler
-
- This section will describe how to write a Dynamic Link Library which
- does not conform to the APCS protocols. If you are writing a DLL in
- assembler for use with APCS-conforming clients then the previous
- section will be more applicable to you.
-
- If you are writing code which does not conform to APCS, you will not
- be able to take advantage of a lot of the support offered by the
- DLLManager. However, by doing this, you will be able to overcome
- the restrictions imposed by the DLLManager’s APCS support (for
- example, you cannot implement coroutines using the standard support
- functions because of the requirement for strict call-return
- discipline).
-
- Re-entrancy
-
- The foregoing discussion of dynamic linking has glossed over one of
- the important properties which dynamically linked code must have −
- it must be able to maintain a separate state for each of its client
- applications. It will help to define some terminology: we say that
- a routine is threaded after it has been called, but before it
- returns to its caller. Since RISC OS is a multitasking environment,
- it is conceivable that a routine in a DLL is threaded by more than
- one client simultaneously. Such a routine must be able to correctly
- locate its state information for each client. Code that can cope
- with this is said to be re-entrant.
-
- A routine will usually keep temporary data in or relative to
- registers. Since each client will see a different set of register
- values, this causes no problems for re-entrancy. The difficulty
- comes in trying to maintain the library’s persistent state.
-
- The recommended approach is to collect all your library’s data areas
- together, and keep their location in or relative to a register. This
- location should be set up when the library is initialised by a
- client. The client can then pass this address to the library when
- it makes external calls.
-
- Important points to note
-
- Since you are not using the DLLManager’s APCS support facilities, you
- will not require the entry veneers for your routines. These entry
- veneers are normally generated automatically by cdll. To prevent
- cdll from generating these veneers, you must put the keyword
- ‘nonAPCS’ in your DLL definition file, outside of any sections
- enclosed in braces.
-
- You should note that the automatic loading of DLLs is a property of
- the SDLS Shared C Library stubs. You should provide a means for
- client applications to find their DLLs if they are not using these
- stubs. Details on how this automatic startup works can be found in
- the reference section.
-
- _____________________________________________________________________________
-
-
- Extension DLLs
-
-
- Introduction
-
- As well as providing facilities for the implementation of shared
- libraries, the Straylight Dynamic Linking System provides a method
- by which applications may easily load extension code if it is
- required. Such extensions are called extension DLLs and might
- provide further facilities which may not always be required. In
- addition, you might publish the interface to your application and
- allow extensions to it to be written by third parties.
-
- A DLL containing a shared library is loaded into the RMA, where it
- can be accessed by all its clients. In contrast, extension DLLs are
- loaded into its client’s application space − it is therefore local
- to that application. This chapter will describe how to write both
- extension DLLs and applications which make use of them. It is
- expected that the reader is familiar with the material presented in
- the previous two chapters.
-
-
- Application entry points
-
- In contrast to shared DLLs, where the DLL defines its interface to
- clients, an application making use of extension DLLs will need to
- define an interface to its libraries. It does this by declaring
- named entry points, in a similar way to a shared library. Extension
- DLLs will find these entry points and so be able to communicate with
- the application.
-
- You define an application’s entry points by creating a cdll
- definition file, containing the ‘exports’ and ‘objects’ sections.
- You can then build a ‘header’ which you link into your client, which
- defines these entry points to the DLLManager, and a ‘stub’ which is
- linked into the extension DLLs. You can build these files using the
- command:
-
- cdll -app -def <defn file> -hdr <header> -stub <stub>
-
- The DLLLib will automatically register the application’s entry points
- with the DLLManager module when the application starts up. If you
- are not using the APCS support offered by the DLLManager, you should
- see the description of the SWI DLL_RegisterAppEntryTable in the
- reference section.
-
-
- Creating extension DLLs
-
- Creating an extension DLL is not very different from creating a
- shared DLL. The main differences are that you do not create a stub
- for the DLL, and you will need to link in the application’s stub.
- To create only the DLL header and not the stub, use the command:
-
- cdll -def <defn file> -hdr <header file>
-
- (i.e. omit the ‘-stub’ option).
-
-
- Loading extension DLLs
-
- An application is responsible for managing the memory used by its
- extension DLLs. It must find out how large a block is required for
- each extension and allocate memory appropriately. It must also
- allocate memory for the DLL’s data. This is actually much easier
- than it sounds, since DLLLib provides a routine which does all of
- this for you. If you aren’t using DLLLib, you should consult the
- reference section, which contains some example code for doing this.
-
- The DLLLib routine, called _dll_loadExtension, will load a file and
- return a DLL handle, which you can use to reference the DLL in
- future. Once the DLL is loaded, it will remain idle until you call it
- through an entry point. It is usual for an extension DLL to provide
- a single entry point which is called when it is loaded − the name of
- this entry point will be fixed by the application. To find this
- entry point, the application will call the SWI DLL_FindEntry (or the
- DLLLib routine dll_findEntry) with the DLL handle and the entry
- point’s name. The entry point can now be called − the extension can
- then call routines in the application to register its services.
-
- _____________________________________________________________________________
-
-
- Registering names
-
-
- Why bother registering?
-
- Under this system, many things are given names to try to identify
- them. It makes sense therefore that some measures are taken to make
- sure the names are unique. We’ve chosen to use textual names to try
- and give users as wide a choice as possible, although problems may
- still occur. Therefore you should register any names you want to
- use with Straylight to avoid clashes.
-
-
- Who needs to register?
-
- Certainly, any commercial software which uses this system ought to
- register any names it requires. Authors of ‘alternatively
- distributed’ software (e.g. Public Domain, Freeware, Shareware,
- Careware) should register DLL names too − it doesn’t take very much
- to register, and it can save a lot of problems if there’s a clash.
- They don’t have to register client application names, although we do
- recommend that they do.
-
-
- What needs to be registered?
-
- You need to register any of the following names:
-
- Shared DLL names
-
- Since DLLs are identified by name alone once they’re loaded
- into memory, names must be unique. The results of a clash
- here could be catastrophic. All shared DLL names must be
- registered with Straylight.
-
- DLL client names
-
- Applications are identified by name in various *commands,
- and user confusion would be reduced considerably if the
- names were different!
-
- If your client’s application or module name is registered
- with Acorn, then that should be acceptable for use as a DLL
- client name. You should still register in any case.
- Someone else who hasn’t registered with Acorn may already
- have taken your name.
-
- DLL resource subdirectories
-
- Shared DLLs are stored in the !DLLs resource folder with one
- subdirectory for each source of DLLs. The name of the
- subdirectory will typically be the name of the company
- creating the DLLs (e.g. ours is called ‘Straylight’). In the
- event of a directory becoming full (77 DLLs allocated to a
- single source), a new name will be allocated.
-
- ‘Alternatively distributed’ DLLs won’t use this system −
- there are simply too many sources. Instead, the names will
- be allocated as ‘Misc_1’, ‘Misc_2’ etc. You will be given a
- directory name when you register your shared DLL name. DLL
- entry point names do not need to be registered, since an
- entry point name is always passed with a DLL handle to
- resolve into an address. Extension DLL names don’t need to
- be registered either, since the DLLManager is only
- interested in the DLL’s handle in this case.
-
-
- How do I register?
-
- You can register in any of the following ways:
-
- • Telephone or fax: 01926 452639
-
- • By mail, to:
-
- Straylight
- 16, Portland Street
- Royal Leamington Spa
- Warwickshire
- CV32 5HE
-
- • By email, to:
-
- dlls@strylght.demon.co.uk
-
- We do not charge a fee for registration.
-
- _____________________________________________________________________________
-
-
- P A R T I I : R E F E R E N C E M A N U A L
-
- _____________________________________________________________________________
-
- How the system works
-
- Introduction
-
- This section describes how the Straylight Dynamic Linking System
- works. It is not necessary to understand all of this to use SDLS,
- although you may find it interesting anyway.
-
- It is assumed that the reader is already fairly familiar with ARM
- assembler and the ARM Procedure Call Standard (APCS). This section
- will re-iterate some of the points made in earlier chapters.
- However, it goes into considerably greater depth.
-
-
- The basic idea
-
- Sharing code on its own is not difficult − all that is necessary is
- to put the code in shared memory (e.g. the RMA) and allow clients to
- find it. The difficulty lies in maintaining separate areas of data
- for each application (the DLL’s instance data for the application).
- Fortunately, the Acorn ANSI C and ISO Pascal compilers provide a
- facility for relocating data references at run-time: if the -zM
- option is specified on the compiler command line, data references
- such as
-
- LDR a1,dataptr
- ;
- ; Some code...
- ;
-
- dataptr DCD data
-
- are replaced by the (slightly) more complex
-
- LDR a1,dataptr
- LDR ip,[sl,#_Mod$Reloc$Off]
- ADD a1,ip,a1
- ;
- ; Some code...
- ;
-
- dataptr DCD data
-
- By changing the offset contained at [sl,#_Mod$Reloc$Off], the DLLMana
- ger can make the code reference different areas of data. Note that
- the value of _Mod$Reloc$Off is by default −536.
-
- This slight alteration to data referencing code is the only
- difference which the –zM option makes.
-
- The DLLManager module then keeps a table of these data relocations
- for each DLL/client pair. When an external call is made to a DLL,
- control passes through a small entry veneer called _dll_entry, which
- sets up the relocation offset correctly, and inserts an exit veneer
- (_dll_exit) to restore it when the external procedure call returns.
-
-
- Handling exceptional control flow
-
- Unfortunately, normal explicit procedure call is not the only way in
- which control is given to functions. Function pointers must be used
- with care within DLLs and module clients. All external calls except
- those to absolute program images must go through entry and exit
- veneers. Ways of ensuring this using the C language are described
- below.
-
- If your program bypasses the normal function return discipline (e.g.
- by using longjmp) you must ensure that the correct workspace
- relocation is used. The DLLManager maintains a stack for each
- client application, which contains relocations and return addresses.
- If the exit veneer is not called, the stack becomes invalid. Hence,
- applications must save the stack pointer before any return point
- (e.g. setjmp), and restore it if the actual return point is called
- (by checking the result of setjmp in C). This is achieved using the
- _dll_setjmp and _dll_longjmped functions in DLLLib, or using SWIs
- DLL_ReadStackPtr and DLL_SetStackPtr. C++ exception handling will
- not be supported until a way is found to gain control on entry to a
- destructor during exception handling.
-
-
- Identifying applications
-
- For the system to work, it’s necessary for the DLLManager to be able
- to identify which application is currently executing, so that it can
- substitute the correct workspace relocation.
-
- Currently, applications are identified by their start time, as
- returned by SWI OS_GetEnv. This method causes a few problems, since
- RISC OS only keeps a record of the start time of the most recent
- application. Therefore applications must preserve their times over
- any system calls which may start up new applications (e.g.
- Wimp_Poll, OS_CLI etc.) This restriction may be lifted if a better
- way of identifying the current application is found. DLLLib
- provides functions which replace the most common offending calls
- (e.g. system).
-
-
- Dynamic linking
-
- The actual linking process is very simple. The DLLManager module has
- a SWI DLL_FindEntry which locates a named entry point within a
- specified DLL, and returns its address. Data items are not exported
- directly, but it is possible to export functions within the DLL
- which return the addresses of data items.
-
- Looking up entry points by name, however, is a slow process, and not
- one that is really desirable for every procedure call. Therefore,
- the DLLManager provides a SWI DLL_FindFromTable which, when given
- pointers to tables of the appropriate format will load the DLLs
- specified, and fill in a branch table with branch instructions to
- the required entry points.
-
- Since looking up entry points by name is a slow process, and the
- names take up a considerable amount of memory, you can assign a
- small integer value called an ordinal to each routine.
-
- The format of the tables used by DLL_FindFromTable are documented in
- the reference section.
-
-
- How the DLL stubs work
-
- A DLL stub object file contains three AREAs, all with attributes CODE
- and READONLY, called DLL$$ExternalTable, DLL$$Strings and
- DLL$$Stubs. Because the linker joins together AREAs with the same
- name into one big AREA and provides symbols giving the start and end
- addresses of the AREAs, this allows lots of DLL stubs to be linked
- together to make an external DLL table (see the information about
- SWI DLL_FindFromTable). DLL$$ExternalTable contains a single entry in
- the external DLL table. DLL$$Strings contains the name of the DLL
- to load, and the names of the entry points required by the client.
- DLL$$Stubs contains a number of words, into which branch
- instructions into the actual DLL may be inserted at run time. The
- initial value of the entries are the ordinals for the routines to
- link to, where defined. Otherwise, they contain the value &E3A0F000
- − MOV PC,#0 − which will cause a ‘Branch through zero’ error if the
- table is used before it is set up properly.
-
- _____________________________________________________________________________
-
-
- DLL file format
-
-
- Introduction
-
- This chapter documents version 1.01 of the DLL file format.
-
- DLL files consist of three parts:
-
- • A DLL header which describes all the necessary parts of a DLL to
- the DLLManager module
-
- • The actual DLL code
-
- • The initialisation values for the DLL’s data
-
- These parts appear in order within the file.
-
-
- The DLL header
-
- A DLL header contains a fixed size part and a variable size part.
- The fixed size part contains pointers to different sections of the
- variable size part. The fixed size part is the first object in the
- DLL file. It contains a number of 4 byte entries, as follows:
-
- Offset Use
-
- 0 The 4 byte value &004C4C44, which is the string ‘DLL’
- followed by a null byte. This is used to identify valid DLL
- files.
-
- 4 The version number of the DLL file format which this
- DLL file conforms to, multiplied by 100. Thus, version 1.01
- is represented as 101.
-
- 8 The address of the DLL’s name.
-
- 12 The address of the DLL’s author string. This allows an
- author to embed copyright information within a DLL.
-
- 16 The version number of the DLL, multiplied by 100.
- Note that this is distinct from the file format version
- number.
-
- 20 An ARM instruction, normally a branch, which if
- excecuted will initialise the DLL, and correctly set up all
- the absolute addresses within the DLL. This routine is
- entered in SVC mode with R13 pointing to the super visor
- stack and R14 containing a return address and flags.
- Registers R0-R3 and R11 may be corrupted. It is expected
- that this is in fact the standard linker routine
- _Reloc$Code. If your DLL requires no initialisation, this
- instruction may just be MOVS PC,R14.
-
- 24 The address of the DLL’s Shared C Library stubs branch
- table, which is filled in by the DLLManager when the DLL is
- loaded. If the address is lower than the DLL’s base
- address, then it is assumed that there is no Shared C
- Library entry table.
-
- 28 The number of entry points offered by the DLL, and
- flags. If bit 31 is set, the entry veneer table (offset 36)
- is replaced by a table of addresses of routines. This is
- used for non-APCS DLLs.
-
- 32 Pointer to the names of the DLL’s entry points, in order.
- The entry point names are each separated by a single zero
- byte, and the last name is followed by a zero byte. Unnamed
- ‘dummy’ entry points, created by gaps in the ordinals are
- indicated by a byte containing the value ‘1’ instead of a
- null-terminated string.
-
- 36 Pointer to the entry veneers table or routine address
- table. There must be at least one table entry for each
- named entry point, although there may be more entries than
- named entry points.
-
- An entry veneer is 16 bytes long. It must set up the
- environment for the DLL appropriately and call the actual
- code within the DLL to perform the actions appropriate for
- that entry point.
-
- The routine address table (indicated by bit 31 being set in
- the flags word at offset 28) contains a one word address of
- each routine, instead of a 16 byte entry veneer.
-
- An ordinal is simply an index into this table − the actual
- address of a routine is calculated by multiplying the
- ordinal by the size of the table entries (16 for a veneer
- table, 4 for an address table).
-
- 40 Pointer to the base of the external DLL dependency
- table. This table has the same format as that described for
- the SWI DLL_FindFromTable. If the pointer is equal to the
- pointer at offset 44, then there is no external DLL
- dependency table.
-
- 44 Pointer to the limit of the external DLL dependency
- table.
-
- 48 Pointer to the base of the DLL’s data initialisation
- values. This data is copied to the data area allocated for
- the DLL’s instance data to initialise it.
-
- 52 Pointer to the limit of the DLL’s data initialisation
- values. Note that this may be higher than the DLL’s actual
- limit in memory.
-
- 56 Pointer to the base of the DLL’s zero-initialised data
- area. This value is relocated to point into the DLL’s
- instance data area and used to allow zero-initialisation of
- the data.
-
- 60 Pointer to the limit of the DLL’s zero-initialised data
- area.
-
- 64 Pointer to the DLL’s application entry point branch
- table. The format of this table and the table pointed to by
- the next word is described with the SWI
- DLL_SetExtensionTable.
-
- 68 Pointer to the names of the application entry points
- required in the previous table. The variable size part of the
- header contains the entry point names and branch tables
- which are set up on loading the DLL.
-
- _____________________________________________________________________________
-
-
- The cdll tool
-
-
- Introduction
-
- The cdll tool will create AOF files to help you make both Dynamic
- Link Libraries and client applications which use them. It works
- from a script file (called a DLL definition file) which itself may
- be created by cdll.
-
-
- Format of DLL definition files
-
- The syntax of the definition files required by cdll is described
- below:
-
- definitionFile ::= {section}
-
- section ::= nameSection | authorSection |
- versionSection | exportsSection |
- extEntrySection | objectsSection
-
- nameSection ::= ‘name’ string
-
- authorSection ::= ‘author’ string
-
- versionSection ::= ‘version’ {digit} [‘.’ [digit [digit]]]
-
- exportsSection ::= ‘exports’ exportsList
-
- extEntrySection ::= ‘extEntry’ identifierList
-
- objectsSection ::= ‘objects’ identifierList
-
- identifierList ::= ‘{’ {identifier} ‘}’
-
- exportsList ::= ‘{’ {identifier [‘=’ integer]} ‘}’
-
- A string is any collection of characters contained within quotation
- marks (either single or double − it doesn’t matter). If you use a
- single quote to start the string, it may contain double quotes and
- vice versa. If you want the string to contain the type of quote
- that it is delimited by, you must write two quotes in a row. If you
- don’t want to include whitespace characters in the string, you can
- leave out the quotes altogether. This sounds very complicated, but
- it’s really quite simple. Some examples of valid strings will help:
-
- "This string doesn't contain any errors"
-
- 'This string has a "quote"'
-
- '"What''s David doing?" said Sarah.'
-
- unQuotedString
-
- An identifier is any series of characters delimited by whitespace. An
- integer is a sequence of decimal digits − hex integers are not
- allowed. Comments may be inserted anywhere in the file. Comments
- always begin with a whitespace character (to distinguish them from
- strange identifiers). There are two types of comments:
-
- • Line comments start with any one of ‘;’, ‘|’, ‘//’ or ‘#’ and
- extend to the end of the current line.
-
- • Block comments start with ‘/*’ and end with ‘*/’. Whitespace
- characters include spaces, newlines, tabs and formfeeds.
-
- The length of a single line is not limited. The size of a single
- token is limited by the available memory.
-
- Null characters (ASCII 0) are not permitted in the definition file.
-
-
- Creating definition files
-
- Definition files are probably easiest created by using the cdll tool.
- You can create a definition file from any collection of object (AOF)
- and library (ALF) files by using the command
-
- cdll -def <output file> -o <object file>...
-
- This will create a DLL definition file called <output file>
- containing declarations of all the external symbols defined by the
- <object file>s. The symbols are not output in any particular order
-
-
- Definition file sections
-
- The name section
-
- This section defines the name of the DLL described by the file. If
- the file is not being used to describe a DLL, this section is
- ignored and may be omitted.
-
- The name may be at most 10 characters long.
-
- See the section Registering names for more details about DLL names.
-
- The author section
-
- This section may contain any string of up to 49 characters, although
- it is anticipated that this will be used to contain the author’s
- copyright notice or similar string. It is ignored if the file is
- not being used to describe a DLL, and may be omitted under these
- circumstances.
-
- The version section
-
- This section defines the version number of the DLL described by the
- file. If the file is not being used to describe a DLL, this section
- is ignored and may be omitted.
-
- The version number contains a major version number, which is any
- collection of digits, a ‘.’ and between zero and two more digits of
- minor version number.
-
- It is vitally important that this number is kept up to date, and that
- it is increased with every new version released. Failure to do this
- can cause severe problems.
-
- The exports section
-
- This section declares all the symbols exported by the DLL or
- application described by the file.
-
- When creating DLL headers or application entry points (see below),
- this section defines the symbols whose names are to be placed in the
- entry point table. Entry veneers are also created for each of the
- symbols specified. You should not put symbols which do not need to
- be exported to clients in this section − you should use the extEntry
- section for these instead.
-
- Each name decared in this section may have an ordinal specified with
- it. An ordinal is simply an unsigned integer which defines the
- particular entry point uniquely within the DLL or application. Note
- that the ordinals should start at 0 and should form a contiguous
- sequence. Gaps in the sequence cause space to be wasted in the
- entry point table. Using ordinals makes application startup faster
- and uses less memory. However, you must ensure that the ordinal for
- each routine stays the same for all versions of the library.
-
- This section is filled in in no particular order by cdll when
- creating definition files. cdll does not automatically assign
- ordinals to entry point names.
-
- The extEntry section
-
- This section declares routines which require veneers to be called
- externally (e.g. any routine in a DLL which may be called externally
- through a function pointer).
-
- When creating DLL headers (see below), this section defines the
- symbols which must have veneers created for them but which should
- not be included in the entry point table (i.e. they should not be
- called directly by clients).
-
- When creating veneers for DLL clients (e.g. module clients), this
- section defines the symbols which must have veneers created for them
- because they can be called externally.
-
- The objects section
-
- This section gives the names of the object files (both AOF and ALF)
- which contain the symbols declared in the exports and extEntry
- sections. This is so that cdll can check that all of these symbols
- are valid and defined, in an attempt to prevent errors.
-
-
- Creating DLL headers with cdll
-
- DLL headers contain all the information the DLLManager needs to know
- about a particular DLL. These can then be linked with the object
- files which contain the actual DLL code to create the finished DLL.
-
- The command line to create a DLL header from a DLL definition file
- is:
-
- cdll -def <defn file> -hdr <header file>
-
- which creates a DLL header from the DLL definition file <defn file>
- and outputs the DLL header in an AOF file called <header file>. The
- entry veneers for the DLL’s entry points are each given symbols
- formed by prefixing the name of the routine being veneered with the
- string ‘_dllEntry_’, so that for example the routine wimpt_init has
- an entry veneer called _dllEntry_wimpt_init. This applies to
- symbols in both the exports and extEntry sections.
-
-
- Creating DLL stubs with cdll
-
- In order to automate the process of initialising a program which uses
- shared DLLs, it is possible to create tables describing the DLLs
- required by the program. These tables are detected by the
- replacement Shared C Library stubs, which proceed to find the
- required DLLs and fill in branch tables with branches to entry
- points within the DLLs. The tables are contained in AOF files
- called DLL stubs which may be linked with the client’s main code.
- The DLLs are found while the Shared C Library is initialising (i.e.
- before main is called), so that the linking process is entirely
- transparent.
-
- The DLL stubs may be linked in place of an equivalent statically
- linked library to produce the same result, or both could be linked,
- in which case as many external references as possible would be
- resolved through the DLL stubs, with any remaining being resolved by
- the statically linked library in the usual way.
-
- To create a DLL stubs file, use the command
-
- cdll -def <defn file> -stub <stub file>
-
- This creates a DLL stub AOF file called <stub file> for the DLL
- described by <defn file>.
-
- Creating external entry points for clients with cdll
-
- If the client requires that the data relocation be set up correctly
- (e.g. it is a module task and needs to be able to access its module
- workspace), any external calls to the client must be veneered.
- Veneers may be set up by using an abbreviated definition file
- containing only the extEntry and objects sections. The command
-
- cdll -def <defn file> -ext <veneer file>
-
- then creates an AOF file called <veneer file> which contains the
- entry veneers. These are very small (only 16 bytes each), but they
- require a routine in DLLLib for them to work, so remember to link
- this in. For each symbol name named in the <defn file>, this creates
- an entry veneer called _extEntry_name. We recommend you use the
- macro _extEntry defined in dll.h to define these names.
-
- _____________________________________________________________________________
-
-
- The DLLManager module
-
-
- Overview
-
- The DLLManager module offers a simple set of *commands and a
- selection of SWI calls for handling Dynamic Link Libraries. Notes
- about the examples
-
- All the examples in this sections are written using the syntax of the
- Acorn ARM Assembler, rather than that of the standard BASIC
- assembler. This is because programs which use DLLs are more likely
- to be written using the ARM Assembler since its output may be linked
- with programs written in high-level languages.
-
- Most of the examples are given in the form of complete source files
- except that definitions of register names and SWI numbers are
- omitted. You may use the example code in your own programs if you
- want to − that’s what it’s there for.
-
- SWI calls
-
- Some standard conventions should be observed when communicating with
- the DLLManager:
-
- • All strings passed to the DLLManager should be 0-terminated. The
- addresses of such strings do not have to be word aligned.
-
- • All other pointers passed to the DLLManager must be word-aligned.
-
- • Version numbers are expressed as integers by multiplying by 100
- (so version 7.24 would be represented as 724).
-
- • Unless otherwise stated, R0 is always corrupted on exit from a SWI
- call, and other registers are preserved.
-
- • All the SWIs execute in SVC mode, they run with FIQs enabled and
- do not alter the IRQ status. The re-entrancy of the SWI routines
- is not defined, and they should not be used from an interrupt
- routine.
-
- Each SWI call (except DLL_Prologue) has a corresponding function in
- DLLLib which allows the SWI to be used from C. These are documented
- with the SWI here, rather than in the section on DLLLib. All these
- functions have names beginning with ‘dll_’, followed by the name of
- the SWI (without the ‘DLL_’ prefix) with a lower-case first letter.
- They all return a pointer to an os_error structure, which either is
- NULL to indicate that the SWI was successful, or contains error
- information returned by DLLManager.
-
-
- DLL_Find (SWI &4A300)
-
- Links an application to a named shared DLL
-
- From assembler
-
- On entry R0 = pointer to DLL name
- R1 = version number required
-
- On exit R0 = DLL handle for the DLL
-
- From C
-
- Prototype os_error *dll_find(const char *name,
- int version,
- dll *d)
-
- Arguments name = pointer to the DLL name (R0)
- version = version number of DLL to load
- dll = pointer to DLL handle to set
-
- Use
-
- This SWI loads the specified DLL into memory if necessary, and
- returns a handle to it.
-
- The name pointed to by R0 (name) must be either a DLL name (up to 10
- characters long, case-insensitive) or a fully qualified file name (in
- which case the leafname is used as the DLL name).
-
- Only DLLs whose version number is greater than or equal to that given
- in R1 (version) are found.
-
- If the DLL is not currently in memory, it is loaded into the RMA in a
- way similar to that performed by DLL_Load. The file loaded is
- determined by the name pointed to by R0:
-
- • If R0 points to a leafname only, the file loaded is given by
- prefixing the name with ‘DLL:’ (i.e. the variable DLL$Path is
- searched, as set up by the DLLs resource.
-
- • If R0 points to a fully qualified path name, it is assumed that
- this is the name of the file to load. Therefore it is essential
- that the leafname of the DLL file matches the name specified in
- its header. Note that after Finding a DLL, you must supply some
- space for its instance variables using DLL_InstanceVars.
-
- Example of use
-
- The example below shows the loading of a single DLL named ‘Steel’.
-
- ADR R0,steelName
- LDR R1,=104
- SWI DLL_Find
- STR R0,steelHnd
- ;
- ; Carry on with initialisation...
- ;
-
- steelName DCB "Steel",0
- ALIGN
- steelHnd DCD 0
-
-
-
- DLL_FindFromTable (SWI &4A301)
-
- Links an application to a number of DLLs
-
- From assembler
-
- On entry R0 = pointer to start of external DLL block
- R1 = pointer to limit (end+1) of external DLL block
-
- On exit –
-
- From C
-
- Prototype os_error *dll_findFromTable(const dll_table *t,
- int entries)
-
- Arguments table = a pointer to an array of dll_table entries
- entries = the number of entries in this table
-
- Use
-
- Registers your application as wanting to use DLLs, and finds (using
- DLL_Find) the DLLs specified in the external DLL block. R0 and R1
- may be equal, in which case no attempt to find any DLLs is made. The
- entries in the table are as follows:
-
- Table 10.1
-
- The entry point name table consists of a number of 0-terminated
- strings concatenated together. The table is terminated by a
- zero-length string. Each word in the branch table is filled in turn
- with a branch instruction to the address of the next named entry
- point.
-
- If the initial value of a word in the branch table is a valid ordinal
- value (i.e. it is lower than the number of entry points declared by
- the DLL), it is interpreted as such and the entry is resolved
- without looking up a name. If the final entry is a valid ordinal,
- there must be an additional out-of- range value on the end (e.g.
- &FFFFFFFF).
-
- The name table should contain a name for each word in the branch
- table which is not an ordinal.
-
- Example of use
-
- The example code is very similar to that used by the DLLLib library
- to load in any DLLs specified in cdll-created DLL stubs files.
-
- IMPORT |DLL$$Data$$Base|
- IMPORT |DLL$$Data$$Limit|
- IMPORT |x$stack_overflow|
- IMPORT giveMemory
-
- AREA |Example$$Code|,CODE,READONLY
-
- ; linkAll
- ;
- ; On entry: --
- ; On exit: a1 == 0 for success, or pointer to error block
-
- EXPORT linkAll
- linkAll ROUT
-
- ; --- Standard APCS header ---
-
- MOV ip,sp
- STMFD sp!,{fp,ip,lr,pc}
- CMP sp,sl
- BLLT |x$stack_overflow|
- SUB fp,ip,#4
-
- ; --- Load DLLs as required ---
-
- LDR a1,|DLL$$Data$$Base| ;Find base of the DLL
- table
- LDR a2,|DLL$$Data$$Limit| ;Find the end of the
- table
- SWI XDLL_FindFromTable ;Load the DLLs we wan
- t
- LDMVSDB fp,{fp,sp,pc}^ ;If it failed, return
- error
-
- ; --- Now allocate workspace for them ---
- ;
- ; We use the giveMemory code shown in the
- ; example for SWI DLL_InstanceVars for this
-
- BL giveMemory ;Set up DLL instance
- vars
- LDMDB fp,{fp,sp,pc}^ ;Return with that err
- or code
-
- LTORG
-
- END
-
-
-
- DLL_Load (SWI &4A302)
-
- Loads a DLL into an application’s memory (for extendible applications
- )
-
- From assembler
-
- On entry R0 = pointer to block of memory
- R1 = pointer to filename of DLL
-
- On exit –
-
- From C
-
- Prototype os_error *dll_load(void *buffer,
- const char *name)
-
- Arguments buffer = pointer to a block in which to load the DLL
- name = the name of the file containing the DLL
-
- Use
-
- Loads a dynamic link library into a block of memory. This low-level
- operation is for occasions when you don’t want a DLL to be shared
- (e.g. if it contains user-provided extensions to a specific
- application). The block pointed to by R0 (buffer) needs to be 20
- bytes larger than the DLL itself (you should have already found the
- size of the DLL file using OS_File). This call will load, check and
- relocate the DLL. Note that you will need to supply the DLL with
- its workspace using DLL_Info and DLL_SetInstanceVars.
-
- You can free the space used by the DLL at any time if you don’t want
- to use it any more – no data structures are set up by the
- DLLManager. Note that the DLL loaded may cause other DLLs to be
- loaded using DLL_Find, and so, after calling DLL_Load, you should
- enter a DLL_InstanceVars loop to allocate instance variables for
- them.
-
- Example of use
-
- The example below is very similar to the implementation of the
- _dll_loadExtension function in DLLLib. It demonstrates how to load
- an extension DLL and initialise it properly.
-
- IMPORT |x$stack_overflow|
- IMPORT malloc
- IMPORT free
- IMPORT giveMemory
-
- AREA |Example$$Code|,CODE,READONLY
-
- ; loadLocal
- ;
- ; On entry: a1 == pointer to name of DLL to load
- ; On exit: a1 == DLL handle for DLL, or 0 for failure
-
- EXPORT loadLocal
- loadLocal ROUT
-
- ; --- APCS header ---
-
- MOV ip,sp
- STMFD sp!,{v1-v3,fp,ip,lr,pc}
- SUB fp,ip,#4
- CMP sp,sl
- BLLT |x$stack_overflow|
-
- ; --- Find the size of the DLL file ---
-
- MOV v3,a1 ;Keep the name pointe
- r safe
- MOV a2,a1 ;Point to the filenam
- e
- MOV a1,#17 ;Get information on f
- ile
- SWI XOS_File ;Get the information
- BVS %10loadLocal ;If it failed, return
- CMP a1,#1 ;Make sure it found a
- file
- BNE %10loadLocal ;If not, make an erro
- r
-
- ; --- Allocate a block for the DLL ---
-
- ADD a1,v1,#20 ;Allow space for DLLM
- anager
- BL malloc ;Allocate the memory
- CMP a1,#0 ;Was there enough mem
- ory?
- BEQ %10loadLocal ;No -- return unhappy
- MOV v2,a1 ;Keep hold of the poi
- nter
-
- ; --- Load the DLL into the block ---
-
- MOV a2,v3 ;Point to the filenam
- e
- SWI XDLL_Load ;Load the DLL and set
- it up
- BVS %11loadLocal ;If it failed, tidy u
- p
-
- ; --- Allocate workspace for the DLL ---
-
- MOV a1,v2 ;Get the 'DLL handle'
- SWI XDLL_Info ;Find out about the D
- LL
- MOV a1,v1 ;Get the workspace si
- ze
- BL malloc ;Allocate the memory
- CMP a1,#0 ;Was there enough?
- BEQ %11loadLocal ;No -- tidy everythin
- g up
- MOV v1,a1 ;Look after the point
- er
- MOV a2,a1 ;Point to this new bl
- ock
- MOV a1,v2 ;Point to the DLL blo
- ck
- SWI XDLL_SetInstanceVars ;Attach the workspace
-
- ; --- Allocate space for new DLLs loaded ---
- ;
- ; Here we use the giveMemory function shown
- ; in the example code for DLL_InstanceVars
-
- BL giveMemory ;Set up new shared DL
- Ls
- CMP a1,#0 ;Did that fail?
- BNE %12loadLocal ;Yes -- tidy everythi
- ng up
-
- ; --- Return the DLL handle to the caller ---
-
- MOV a1,v2 ;Point to the DLL blo
- ck
- LDMDB fp,{v1-v3,fp,sp,pc}^ ;Return to the caller
-
- ; --- Free DLL's instance vars ---
-
- 12loadLocal MOV a1,v1 ;Point to the workspa
- ce
- BL free ;Free the block
- ; Drop through to free DLL block
-
- ; --- Free DLL block and return to caller ---
-
- 11loadLocal MOV a1,v2 ;Point to the DLL blo
- ck
- BL free ;Free that up nicely
- ; Drop through to exit failed
-
- ; --- Return to caller -- we failed ---
-
- 10loadLocal MOV a1,#0 ;Return a NULL pointe
- r
- LDMDB fp,{v1-v3,fp,sp,pc}^ ;Return to caller
-
- LTORG
-
- END
-
-
-
- DLL_Lose (SWI &4A303)
-
- Informs DLLManager that an application no longer needs a shared DLL
-
- From assembler
-
- On entry R0 = DLL handle of DLL to remove
-
- On exit –
-
- From C
-
- Prototype os_error *dll_lose(dll d)
-
- Arguments d = DLL handle of DLL to remove
-
- Use
-
- Removes your application from the list of those using the specified
- DLL. If your application was the only one using the DLL, then it
- will be removed from memory.
-
- Example of use
-
- The example shows how the DLL loaded in the example for DLL_Find
- might be disposed of later.
-
- ;
- ; Finalisation code...
- ;
- LDR R0,steelHnd
- SWI DLL_Lose
- ;
- ; More code...
- ;
-
- DLL_AppDying (SWI &4A304)
-
- Informs the DLLManager that the application is quitting
-
- From assembler
-
- On entry –
-
- On exit –
-
- From C
-
- Prototype os_error *dll_appDying(void)
-
- Arguments −
-
- Use
-
- Makes the DLLManager forget about your application, Losing any DLLs
- it Found for you etc.
-
-
- DLL_GiveCLibData (SWI &4A305)
-
- Informs the DLLManager where the application’s C Library data is
-
- From assembler
-
- On entry R0 = pointer to start of C Library data
-
- On exit –
-
- From C
-
- Prototype os_error *dll_giveCLibData(void *data)
-
- Arguments data = pointer to start of C Library data
-
- Use
-
- Declares to the DLLManager the position of the C Library data for
- this application. This information is used by DLL_FindCLibData to
- locate exported CLib data from within a DLL.
-
- The Shared C Library data area is considered to begin at the address
- of __errno. Thus it is the address of __errno that should be passed
- in R0.
-
- Example of use
-
- The example code fragment below just sets up the Shared C Library
- address for the current application.
-
- LDR R0,=|__errno|
- SWI XDLL_GiveCLibData
- ;
- ; Continue with initialisation...
- ;
-
-
- DLL_FindCLibData (SWI &4A306)
-
- Finds the C Library data for the current application
-
- From assembler
-
- On entry –
-
- On exit R0 = pointer to start of C Library data
-
- From C
-
- Prototype os_error *dll_findCLibData(void **p)
-
- Arguments p = *p is set up to point to C Library data
-
- Use
-
- Finds the client’s C Library data, as set up with DLL_GiveCLibData.
- It is an error to call this SWI without the application having
- called DLL_GiveCLibData.
-
- The Shared C Library data is considered to begin at the address of
- __errno, and thus this call actually gives the address of __errno.
- It is mainly used by the DLLLib functions _dll_errno, _dll_iob,
- _dll_ctype and _dll_hugeval to locate items of the client’s C
- Library data from within a DLL.
-
-
- DLL_InstanceVars (SWI &4A307)
-
- Sets up workspace for the shared DLLs linked to the current
- application
-
- From assembler
-
- On entry R0 = First call: −
- Subsequent calls: pointer to a block of
- size given by previous
- call, or 0 if not enough
- memory was available
- R4 = First call: 0 for first call
- Subsequent calls: R4 value from previous call
-
- On exit R0 = size of block required for instance variables
- R4 = 0 (no more DLLs to allocate for) or value to
- pass to next call
-
- From C
-
- Prototype os_error *dll_instanceVars(void *buffer,
- int *size,
- int *magic)
-
- Arguments buffer = a pointer to a block of memory whose size is
- size as returned by the previous call
- size = pointer to an integer to fill in with the size
- of the next block to allocate
- magic = pointer to an integer, initially zero, to
- pass back to the next call. magic will be
- reset to 0 to indicate the end of the loop.
-
- Use
-
- The call should be used in a loop. Each time the call returns R4
- non-zero, R0 bytes of data should be allocated and passed to the
- next call. R4 is used here because it is preserved over calls to
- APCS routines (e.g. malloc). See the flowchart in figure 10.1 for
- the recommended sequence.
-
- Figure 10.1: Flowchart for calling DLL_InstanceVars
-
- If you cannot allocate enough memory, you have two choices:
-
- • Abort the loop and report an error
-
- • Pass R0 (buffer) back to DLL_InstanceVars as 0. DLL_InstanceVars
- will return an error.
-
- Note that this call will only allocate space for instance variables
- loaded using DLL_Find. You have to use DLL_SetInstanceVars for DLLs
- loaded by DLL_Load.
-
- Example of use
-
- The example below shows the implementation of the giveMemory function
- used in the examples for DLL_Load and DLL_FindFromTable.
-
- IMPORT |x$stack_overflow|
- IMPORT malloc
-
- AREA |Example$$Code|,CODE,READONLY
-
- ; giveMemory
- ;
- ; On entry: --
- ; On exit: a1 == 0 for success, or pointer to error
-
- EXPORT giveMemory
- giveMemory ROUT
-
- MOV ip,sp
- STMFD sp!,{v1,fp,ip,lr,pc}
- SUB fp,ip,#4
- CMP sp,sl
- BLLT |x$stack_overflow|
-
- MOV v1,#0 ;R4 starts off as 0
- 00giveMemory SWI XDLL_InstanceVars ;Get another block si
- ze
- LDMVSDB fp,{v1,fp,sp,pc}^ ;If it failed, return
- CMP v1,#0 ;Is that the end now?
- MOVEQ a1,#0 ;Yes -- exit with no
- error
- LDMEQDB fp,{v1,fp,sp,pc}^ ;Return to caller
- BL malloc ;Allocate the block
- B %00giveMemory ;And go round for ano
- ther
-
- LTORG
-
- END
-
-
- DLL_SetInstanceVars (&4A308)
-
- Sets up workspace for a non-shared DLL
-
- From assembler
-
- On entry R0 = DLL handle
- R1 = pointer to block for instance variables
-
- On exit –
-
- From C
-
- Prototype os_error *dll_setInstanceVars(dll d,void *workspace)
-
- Arguments d = the DLL handle
- workspace = pointer to block for instance variables
-
- Use
-
- Provides instance variables for a DLL which was loaded using DLL_Load
- (not DLL_Find or DLL_FindFromTable). The DLL handle of such a DLL
- is the block pointer passed to DLL_Load to load it. You should read
- the required size of the workspace block using DLL_Info.
-
- Example of use
-
- See DLL_Load for an example of using this SWI.
-
-
- DLL_AppData (SWI &4A309)
-
- Informs the DLLManager of the location of the current application’s
- workspace
-
- From assembler
-
- On entry R0 = stack limit pointer (R10 under APCS-R)
-
- On exit –
-
- From C
-
- Prototype os_error *dll_appData(void)
-
- Arguments −
-
- dll_appData finds the stack limit pointer automatically. You do not
- need to specify it yourself.
-
- Use
-
- Declares the application’s data relocation to the DLLManager, so that
- it may be found using DLL_Prologue with a null DLL handle. This is
- required by module tasks which have external entry veneers.
-
- Example of use
-
- This example shows how a typical module might declare its own data
- pointer.
-
- MOV al,sl ;Pass pointer to stack limit
- SWI DLL_AppData ;Register with DLLManager
-
-
- DLL_Prologue (&4A30A)
-
- Part of the standard DLL entry veneer code
-
- From assembler
-
- On entry R0 = return address of this routine
- R1 = pointer to stack limit structure
- R2 = pointer to base of DLL code, or 0
-
-
- On exit R0 = new return address (pointer into DLLManager
- code)
- R1 preserved
- R2 preserved
-
- From C
-
- Use of this SWI from C is not supported.
-
- Use
-
- Used in the DLL prologue code to patch up accesses to instance
- variables. You shouldn’t need to worry about this one too much. R2
- is not a DLL handle, and the relationship between a DLL handle and
- the DLL’s code base address is not defined. This value of R2 is
- chosen because it allows a DLL to find a value which identifies
- itself to DLLManager efficiently. An R2 value of 0 indicates that you
- want to find the variables for the base application (usually a
- module) as registered by DLL_AppData.
-
- Example of use
-
- The example below illustrates how the veneers generated by cdll work.
-
- ; --- Common part of veneers ---
-
- |_dll_common| MOV R0,lr
- MOV R1,sl
- ADR R2,|_dll_base|
- SWI DLL_Prologue
- MOV lr,R0
- LDMFD sp!,{R0-R2}
- MOV pc,ip
-
- ; --- Example entry point ---
-
- EXPORT |_dllEntry_foo|
- IMPORT foo
-
- |_dllEntry_foo| STMFD sp!,{R0-R2}
- LDR ip,[pc]
- B |_dll_common|
- DCD foo
-
-
- DLL_ReadStackPtr (SWI &4A30B)
-
- Reads the DLL stack pointer to allow for exceptional flow control
-
- From assembler
-
- On entry −
-
- On exit R0 = a number suitable for passing to DLL_SetStackPtr
-
- From C
-
- Prototype os_error *dll_readStackPtr(int *sp)
-
- Arguments sp = *sp is set to a value which may be passed to
- dll_setStackPtr.
-
- Use
-
- When a call is made through a DLL or application external entry
- point, the caller’s workspace pointer is saved on a special stack.
- During normal procedure return, this stack is handled transparently
- by the DLLManager. However, if control flow is abnormal (e.g. if
- you use setjmp and longjmp), the jump target may have the wrong data
- pointer.
-
- By saving the stack pointer immediately before a longjmp target (or
- similar), and restoring it after a return via longjmp, this problem
- may be circumvented.
-
- This routine will read a stack pointer in a form which may be later
- passed to DLL_SetStackPtr.
-
- Example of use
-
- _dll_setjmp (see the section on DLLLib below) provides a better way
- of calling this SWI, and you should see that call for an example of
- its use.
-
- DLL_SetStackPtr (&4A30C)
-
- Sets the DLL stack pointer on return via exceptional control flow
-
- From assembler
-
- On entry R0 = a number returned by DLL_ReadStackPtr
- R1 = current stack limit value
-
- On exit −
-
- From C
-
- Prototype os_error *dll_setStackPtr(int sp)
-
- Arguments sp = an integer set up by dll_readStackPtr.
-
- dll_setStackPtr finds the current stack limit automatically. You do
- not need to specify it yourself.
-
- Use
-
- This routine will set the DLL workspace stack pointer from a value
- set up by an earlier call to DLL_ReadStackPtr (q.v. for more
- information). It also sets up the data relocation correctly for the
- stack pointer position. If the stack is returned to top-level, the
- relocation is set from the client’s original relocation (set through
- DLL_AppData).
-
- Example of use
-
- _dll_longjmped (see the section on DLLLib below) provides a better
- way of calling this routine. See _dll_setjmp for an example of the
- use of this routine.
-
-
- DLL_NameApp (SWI &4A30D)
-
- Gives a name to the current application
-
- From assembler
-
- On entry R0 = pointer to application name
-
- On exit –
-
- From C
-
- Prototype os_error *dll_nameApp(const char *name)
-
- Arguments name = pointer to the application’s name.
-
- Use
-
- Sets up the current application as having the given name. This name
- is used by various DLLManager *commands.
-
- The name may be up to 10 characters long, it must not contain spaces
- or control characters and it must be unique in a case-insensitive
- way.
-
- For details on the requirements for names, see the chapter
- Registering names.
-
-
- DLL_Info (SWI &4A30E)
-
- Find information about a specified DLL
-
- From assembler
-
- On entry R0 = DLL handle
-
- On exit R0 preserved
- R1 = pointer to DLL’s name
- R2 = version number of DLL
- R3 = pointer to DLL’s copyright string
- R4 = size of DLL’s instance variable requirements
-
- From C
-
- Prototype os_error *dll_info(dll d,dll_infostr *i)
-
- Arguments d = the handle of the DLL about which to find
- information
- i = a pointer to an information structure to fill in
-
- dll_infostr fields
- dll d = the DLL handle passed as d above
- char *name = pointer to the DLL’s name
- int version = version number of the DLL
- char *author = pointer to the DLL’s author string
- unsigned instSize = size in bytes of the DLL’s workspace
-
- Use
-
- Gives pieces of information of varying usefulness about the specified
- DLL.
-
- Example of use
-
- See DLL_Load for an example of using this SWI.
-
-
- DLL_FindEntry (SWI &4A30F)
-
- Find a named entry point in a DLL
-
- From assembler
-
- On entry R0 = DLL handle
- R1 = pointer to entry point name
-
- On exit R0 = pointer to entry point in DLL
-
- From C
-
- Prototype os_error *dll_findEntry(dll d,
- const char *name,
- void (**entry)())
-
- Arguments d = the DLL in which to find an entry point
- name = pointer to the name of the entry point to find
- entry = *entry is set to point to the entry point
-
- If the entry point has a non-void return value, you will need to
- typecast your entry argument.
-
- Use
-
- Finds a named entry point in a specified DLL. This is useful if your
- application uses DLLs to allow user extensions – you could require
- that all DLLs used for this purpose export an entry point (say
- ‘app_main’) and use this call to find and call it, possibly
- supplying your own set of entry points.
-
- Entry point names are case-sensitive, in support of case-sensitive
- languages like C.
-
- Example of use
-
- The example below locates a named entry point and calls it, passing a
- single integer argument.
-
- AREA |Example$$Code|,CODE,READONLY
-
- ; callEntry
- ;
- ; On entry: a1 == DLL handle containing entry point
- ; a2 == name of entry point
- ; a3 == parameter to pass to entry in a1
- ; On exit: a1 == pointer to an error block if the entry
- ; point could not be found, or value of a1
- ; on return from entry point
-
- EXPORT callEntry
- callEntry ROUT
-
- ; --- Locate the entry point ---
-
- MOV ip,lr ;Look after the link
- register
- SWI XDLL_FindEntry ;Locate entry point a
- ddress
- MOVVS pc,ip ;If it failed, return
- error
-
- ; --- Call the entry point ---
-
- MOV lr,ip ;Restore return addre
- ss
- MOV a2,a1 ;Keep entry point add
- ress
- MOV a1,a3 ;Put argument in a1
- MOV pc,a2 ;And exit via the ent
- ry point
-
- LTORG
-
- END
-
- DLL_SaveHandle (SWI &4A310)
-
- Finds the current application’s handle so that it can be restored
- later
-
- From assembler
-
- On entry −
-
- On exit R0 = the current application’s handle
-
- From C
-
- Prototype os_error *dll_saveHandle(int *handle)
-
- Arguments handle = *handle is filled in with the application
- handle
-
- Use
-
- This SWI allows an application to make sure that its handle is
- preserved over OS calls which might otherwise corrupt it. The
- application handle must be valid during any calls to DLLManager with
- the single exception of DLL_RestoreHandle.
-
- The requirement to save the handle may be dropped if an alternative
- method of identifying applications is used instead.
-
- Example of use
-
- The example below shows how to call an arbitrary *command while
- ensuring that the application handle is preserved.
-
- IMPORT |x$stack_overflow|
- IMPORT system
-
- ; safeCommand
- ;
- ; On entry: a1 == pointer to command string to call safely
- ; On exit: a1 == 0 if all went well, or a system-style
- ; return code otherwise
-
- EXPORT safeCommand
- safeCommand ROUT
-
- ; --- Create a new stack frame ---
-
- MOV ip,sp
- STMFD sp!,{v1,fp,ip,lr,pc}
- SUB fp,ip,#4
- CMP sp,sl
- BLLT |x$stack_overflow|
-
- ; --- Get my current handle ---
-
- MOV a2,a1 ;Look after command s
- tring
- SWI DLL_SaveHandle ;Get my application h
- andle
- MOV v1,a1 ;Save that away for a
- bit
-
- ; --- Perform the command ---
-
- MOV a1,a2 ;Restore the command
- pointer
- BL system ;Execute the command
- MOV a2,a1 ;Save the return code
- away
-
- ; --- Restore my application handle ---
-
- MOV a1,v1 ;Get the application
- handle
- SWI DLL_RestoreHandle ;Restore to previous
- value
-
- ; --- Return to caller ---
-
- MOV a1,a2 ;Reinstate system ret
- urn val
- LDMDB fp,{v1,fp,sp,pc}^ ;Return to caller
-
- LTORG
-
- END
-
-
- DLL_RestoreHandle (SWI &4A311)
-
- Sets the current application’s handle from an earlier saved copy
-
- From assembler
-
- On entry R0 = the application handle to set
-
- On exit −
-
- From C
-
- Prototype os_error *dll_restoreHandle(int *handle)
-
- Arguments handle = pointer to an integer set up by
- dll_saveHandle
-
- Use
-
- This SWI allows an application to restore its handle after OS calls
- which might have corrupted it. The application handle must be valid
- during any calls to DLLManager with the single exception of
- DLL_RestoreHandle.
-
- The requirement to save the handle may be dropped if an alternative
- method of identifying applications is used instead.
-
- Example of use
-
- See SWI DLL_SaveHandle for an example of using this SWI.
-
-
- DLL_FindInstanceVars (SWI &4A312)
-
- From assembler
-
- On entry R0 = DLL handle
-
- On exit R0 = pointer to the DLL’s instance variable area
-
- From C
-
- Prototype os_error *dll_findInstanceVars(dll d,int **addr)
-
- Arguments d = a DLL handle
- size = address to store the instance variable area
- pointer
-
- Use
-
- Finds the address of an extension DLL’s instance variables. This
- saves you from having to store this address separately so you can
- free it again later.
-
- DLL_RegisterAppEntryTable (SWI &4A313)
-
- From assembler
-
- On entry R0 = pointer to an entry point address list
- R1 = pointer to the entry point name list
-
- On exit −
-
- From C
-
- Prototype os_error *dll_registerAppEntryTable(void (**btable)()
- ,
- char *names)
-
- Arguments btable = pointer to address table
- names = pointer to entry point name list
-
- Use
-
- Registers an application’s entry point table with the DLLManager, so
- that DLLs can call entry points within the client.
-
- The name list contains the names of the entry points, in order,
- separated by single null bytes. Dummy entries, for unused entry
- points, may be indiciated by a single byte containing the value ‘1’.
- The whole list is terminated by a zero length entry. The address
- table contains the addresses of the entry points in order.
-
- The entry point table contains four byte addresses of the actual
- routines. Ordinals are simply indices into this table.
-
-
- DLL_FindAppEntry (SWI &4A314)
-
- From assembler
-
- On entry R0 = pointer to entry point name
-
- On exit R0 = pointer to entry point address
-
- From C
-
- Prototype os_error *dll_findAppEntry(char *name,void (**func)()
- )
-
- Arguments name = pointer to entry point name
- func = address to store the entry point address
-
- Use
-
- Looks up a named entry point within the currently executing client
- application.
-
-
- DLL_SetExtensionTable (SWI &4A315)
-
- From assembler
-
- On entry R0 = pointer to branch table to fill in
- R1 = pointer to name list
-
- On exit −
-
- From C
-
- Prototype os_error *dll_setExtensionTable(void (**btable)(),
- char *names)
-
- Arguments btable = pointer to branch table to fill in
- names = pointer to name list
-
- Use
-
- Fills in an area of memory with branch instructions to specified
- entry points within the currently executing client application.
-
- Each entry in the branch table initially lower than &1000 is
- considered to be the ordinal of the entry point to find, thus
- bypassing the normal name lookup. Entries greater than &1000 are
- filled in by finding the entry point whose name matches the next
- entry in the name table.
-
- The name list contains entry point names each separated by a single
- zero byte, one for each entry in the branch table not interpreted as
- an ordinal. The whole list is terminated by a zero-length entry.
- If the branch table initially only contains ordinals, it must be
- terminated by a value greater than &1000 and the name list contains
- only a zero byte.
-
-
- *Commands
-
- *DLLs
-
- Lists the shared DLLs currently in memory
-
- Syntax
-
- *DLLs [<application name>]
-
- Parameters
-
- application name = the name of an application (as shown by *DLLApps)
-
- Use
-
- Shows a list of either all shared DLLs currently loaded if no
- application name is specified or just those associated with the named
- application, together with a small quantity of information about
- each.
-
- Application names are not case-sensitive.
-
- Examples
-
- *DLLs (shows all shared DLLs loaded)
-
- *DLLs Glass (shows the shared DLLs used by the application
- ‘Glass’)
-
-
- *DLLApps
-
- Shows the current DLL client applications.
-
- Syntax
-
- *DLLApps [<DLL name>]
-
- Parameters
-
- DLL name = the name of a DLL (as shown by *DLLs)
-
- Use
-
- Lists either the names of all DLL client applications (if no DLL name
- is specified) or the applications using the named DLL. If you specify
- a DLL name, the version of the DLL used by each client is also
- displayed (since multiple versions of a DLL may in memory
- simultaneously).
-
- If a client application has not registered a name with the
- DLLManager, its name is shown as ‘<Untitled>’.
-
- DLL names are not case-sensitive.
-
- Examples
-
- *DLLApps (shows names of all DLL client apps currently
- running)
-
- *DLLApps Steel (shows the names of the current clients of the DLL
- called ‘Steel’, together with the versions of Steel
- which they are using)
-
-
- *DLLInfo
-
- Shows information about a named DLL
-
- Syntax
-
- *DLLInfo <DLL name>
-
- Parameters
-
- DLL name = the name of a shared DLL (as shown by *DLLs)
-
- Use
-
- Shows a large quantity of information about the latest version of a
- DLL currently loaded:
-
- • Its name
-
- • Its author/copyright string
-
- • Its version number
-
- • The number of clients it has
-
- • The names of all its entry points (this can be quite a long list)
-
- DLL names are not case-sensitive.
-
- Example
-
- *DLLInfo Steel (shows vast quantities of information about Steel)
-
-
- *DLLKillApp
-
- Informs the DLLManager that an application has quit
-
- Syntax
-
- *DLLKillApp <Application name>
-
- Parameters
-
- Application name = the name of an application (as shown by *DLLApps).
-
- Use
-
- Terminates the named application’s use of the DLLManager. It
- performs the same actions as SWI DLL_AppDying, and is mainly useful
- if an application ended abnormally (so that it failed to call
- DLL_AppDying properly).
-
- You should ensure that the application named is not running − if it
- is, it will probably crash the machine badly once it regains control.
-
- Application names are not case-sensitive.
-
- Example
-
- *DLLKillApp VeryBuggy
- (kills ‘VeryBuggy’, because it wasn’t able to close
- itself down)
-
-
- *DLLReset
-
- Resets the DLLManager
-
- Syntax
-
- *DLLReset
-
- Parameters
-
- −
-
- Use
-
- Resets the DLLManager module, removing all shared DLLs from memory,
- and freeing up lots of memory.
-
- This is useful in the unlikely event that the DLLManager goes out of
- control, or if you have lots of applications which haven’t closed
- them selves down properly. Note that you can’t just RMReinit the
- DLLManager because it checks to find out if it it still in use.
-
- If there are any applications using shared DLLs, using this command
- will make them all crash very badly when they regain control. You
- have been warned.
-
- Example
-
- *DLLReset (resets the DLLManager)
-
-
- *DLLEnsure
-
- Finds out if a DLL is available for use
-
- Syntax
-
- *DLLEnsure <DLL name> <version>
-
- Parameters
-
- DLL name = either a normal DLL name (as shown by *DLLs) or a fully
- qualified pathname version = a decimal version number
-
- Use
-
- Finds out whether a DLL with the name and version specified is
- available. The searching is the same as for the SWI DLL_Find. In
- summary:
-
- • If DLL name is a full pathname, a normal DLL name is set as the
- leafname
-
- • If DLL name is a normal DLL name, a pathname is set up by
- prefixing DLL name with ‘DLL:’.
-
- • The shared DLLs in memory are searched for the normal DLL name and
- version specified
-
- • If it wasn’t found there, the file specified by the pathname is
- opened, and examined to see if it is of a high enough version.
-
- If the search was successful, the command stops and control returns.
- If it failed, and error is returned.
-
- This is useful for inserting in !Run files for applications.
-
- Example
-
- *DLLEnsure Steel 0.02
- (make sure version 0.02 or higher of DLL Steel is
- available)
-
- _____________________________________________________________________________
-
-
- The DLLLib library
-
-
- Overview
-
- The library is split internally into three sections:
-
- • An APCS interface to the DLLManager SWIs
-
- • Support functions provided for DLL clients
-
- • ‘Behind the scenes’ support functions for the use of the DLL stubs
-
- All the DLLLib functions and macros are defined in the dll.h header
- file (file DLL.h.dll in the distribution archive), which should be
- made available to C programs via the C$Path mechanism. The actual
- code for DLLLib is held within the file DLLLib.o.DLLLib in the
- Dynamic Linking System distribution archive. To link the library in,
- just add the filename of the library to the linker or compiler
- command line. If you use Acorn’s Make application, you simply drag
- the DLLLib file to the Add icon in the Project dialogue box.
-
- Important note
-
- In order to perform its work, the DLLLib library must export private
- support functions for the use of the replacement Shared C Library
- stubs.
-
- All DLLLib functions and macros have names beginning with the
- characters ‘_dll’, ‘_ext’ or ‘dll_’. In order to allow for new
- features to be added to the the library, you should consider all
- identifiers beginning with these characters to be reserved, and not
- try to define them in your own code.
-
- Support macros
-
- So that an application can easily be written to use either dynamic
- linking or static (standard) linking, many of the support function
- definitions are only enabled if the macro _DLL is defined before
- including dll.h. To allow for creating libraries which may be
- compiled to be either dynamically or statically linked, the macros
- _dllEntry and _dll_static are provided. _dllEntry(name) will return
- either the name of entry veneer corresponding to entry point name or
- name itself, depending on whether _DLL is defined. This can be
- useful for passing addresses of functions. e.g.
-
- void mylib_init(void)
- {
- /*
- * Some code...
- */
- atexit(_dllEntry(mylib__exit));
- }
-
- _dll_static is empty if _DLL is defined, and returns static if it
- isn’t. It is useful for declaring internal functions, to which you
- pass function pointers to other functions (e.g. mylib__exit in the
- example given above).
-
- The entry veneers created for these functions need to be able to have
- the function’s name exported, so when you are creating a DLL, they
- must be externally visible.
-
- The macro _extEntry() performs a similar job to _dllEntry() −
- _extEntry(name) becomes _extEntry_name if _DLL is defined, and name
- if it isn’t.
-
- DLLManager SWI interface
-
- All of the interface functions return a pointer to an os_error
- structure, which is NULL if the call was successful. Each call
- corresponds to a DLLManager SWI, and is documented with it above.
-
- Other support functions
-
- The call interface to these functions is defined in terms of C, since
- they all conform to APCS-R.
-
- If calling from assembler, load the arguments into registers R0
- onwards in the same order as they are defined in the C prototype.
- On exit, R0 contains the return value or is corrupted and R1-R3 and
- R12 are cor rupted also.
-
- The following functions may be replaced by macros, although they are
- guaranteed not to multiply re-evaluate their arguments.
-
- _dll_setjmp
-
- Prototype
-
- int _dll_setjmp(void)
-
- Arguments
-
- −
-
- Return value
-
- An integer value representing the current DLL stack pointer in an
- undefined manner. This value is suitable for passing to
- _dll_longjmped.
-
- Use
-
- Returns the current state of the DLL stack, so that it may be
- restored later via _dll_longjmped. The format of the return value
- is unspecified, and should not be relied upon.
-
- Example of use
-
- See _dll_longjmped below for an example of use.
-
-
- _dll_longjmped
-
- Prototype
-
- void _dll_longjmped(int ptr)
-
- Arguments
-
- ptr = a stack pointer returned by _dll_setjmp.
-
- Return value
-
- −
-
- Use
-
- Restores the DLL stack after an exceptional procedure return (e.g.
- through longjmp).
-
- Example
-
- int stackptr=_dll_setjmp(); /* Read DLL stack pointer */
- jmp_buf j; /* Record stack frame info */
-
- /*
- * Some setting up...
- */
-
- if (!setjmp(j))
- {
- /*
- * Some stuff involving longjmp...
- */
- }
- else
- {
- /* --- Someone longjmped here --- */
-
- _dll_longjmped(stackptr); /* Reset DLL stack nicely */
-
- /*
- * Do anything else to restore the state
- */
- }
-
-
- _dll_appspace
-
- Prototype
-
- void _dll_appspace(void)
-
- Arguments
-
- −
-
- Return value
-
- −
-
- Use
-
- Registers the location of the caller’s static variables with the
- DLLManager so that the relocation is set up properly if the client
- is entered through an _extEntry-type veneer.
-
- This is only of use to applications which are compiled with the -zM
- compiler option (i.e. module applications), and even then, the DLL
- stubs perform this task on initialisation, unless the client’s DLL
- table is empty.
-
- Therefore, you will only need to make this call if:
-
- • You are writing a module application, and
-
- • You are not using any shared DLLs through the normal stub
- mechanism, and
-
- • You are using DLLs (either shared or nonshared).
-
-
- _dll_clibdata
-
- Prototype
-
- void _dll_clibdata(void)
-
- Arguments
-
- −
-
- Return value
-
- −
-
- Use
-
- Registers the location of the client’s copy of the Shared C Library’s
- instance data with the DLLManager so that any DLLs which require acce
- ss
- to this data (e.g. if they output to stderr) can find it.
- This is normally performed automatically by the DLL stubs, unless the
- client’s DLL table is empty. You will therefore only need to use thi
- s call if
- you are using DLLs without the standard DLL stub mechanism.
-
-
- _dll_setname
-
- Prototype
-
- void _dll_setname(const char *name)
-
- Arguments
-
- name = pointer to the application’s name (null-terminated)
-
- Return value
-
- −
-
- Use
-
- Registers the client’s name with the DLLManager. This is not essenti
- al,
- although it is considered to be ‘polite’.
-
- For the rules about client application names, see the chapter Registe
- ring
- names.
-
- Example of use
-
- _dll_setname("Glass");
-
-
- _dll_system
- _dll_ksystem
- _dll_oscli
- _dll_starttask
-
- Prototypes
-
- int _dll_system(const char *command)
- int _dll_ksystem(const char *command,int chain)
- os_error *_dll_oscli(const char *command)
- os_error *_dll_starttask(const char *command)
-
- Arguments
-
- command = pointer to a null-terminated *command. For _dll_system,
- this may be prefixed with the characters ‘CHAIN:’ or
- ‘CALL:’.
- chain = 0 to keep the application in memory while the command
- executes, nonzero to remove the application.
-
- Return value
-
- _dll_system returns the same values as the standard C function
- system. _dll_ksystem returns the same values as _kernel_system.
- _dll_oscli and _dll_starttask return 0 for success, or a pointer to
- a RISC OS-style error structure for failure.
-
- Use
-
- These are all safe ways of calling *commands. Each one is an
- interface to a standard function which calls a *command, but they
- save the application handle around the call, so they are safe to use
- from DLL clients. The relationship is:
-
- Table 11.1
-
- Actually, _dll_oscli and _dll_starttask call the SWIs OS_CLI and
- Wimp_StartTask directly, rather than going through the veneer
- functions.
-
- This is unlikely to make much difference in practice.
- _dll_loadExtension
-
- Prototype
-
- dll _dll_loadExtension(const char *name)
-
- Arguments
-
- name = pointer to the filename of a DLL file
-
- Return value
-
- A DLL handle for the newly loaded DLL, or a NULL pointer if the load
- failed for any reason (e.g. ran out of memory).
-
- Use
-
- This call loads and initialises a local (extension) DLL, and returns
- a handle to it. Space for the DLL is allocated using malloc. The
- DLL handle returned may be used just like any other DLL handle. When
- you are finished with an extension DLL, you can destroy it simply by
- freeing the DLL handle.
-
- Example of use
-
- The example function loads a named extension DLL and initialises it
- by calling a named function (in this case myext_init − this would be
- standard for all the DLLs used by an application), passing it the
- address of a table of function pointers within the main application.
-
- BOOL myapp_loadExtension(char *name,dll *d,widget *w)
- {
- widget (*p)(myapp_entryTable *tbl);
-
- *d=_dll_loadExtension(name);
- if (*d)
- {
- wimpt_noerr(dll_findEntry(d,"myext_init",(void (**)())&p));
- *w=p(&myapp__entryTable);
- }
- return (d ? TRUE : FALSE);
- }
-
-
- _dll_giveMemory
-
- Prototype
-
- void _dll_giveMemory(void)
-
- Arguments
-
- −
-
- Return value
-
- −
-
- Use
-
- Allocates workspace for all the shared DLLs being used by the client
- which have not yet been allocated any. Workspace is allocated using
- malloc. If there is not enough memory, an error is generated, and
- (in C) a SIGOSERROR is raised.
-
-
- _dll_wimpPoll
- _dll_wimpPollIdle
-
- On entry
-
- R0 = Wimp_Poll event mask and flags
- R1 = pointer to block to fill with event data
- R2 = time to return with an idle event (_dll_wimpPollIdle only)
- R3 = pointer to poll word in the RMA, if bit 22 of R0 is set
-
- On exit
-
- R0 = Wimp_Poll event code, or pointer to error block
- V set if an error occurred, or clear otherwise
- Other registers preserved
-
- Use
-
- Provides a ‘safe’ way to call Wimp_Poll and Wimp_PollIdle. The entry
- and exit conditions are the same as those for Wimp_Poll and
- Wimp_PollIdle. In particular, if bit 24 is set in R0 on entry, the
- floating point status and registers F4-F7 are saved (even under
- RISC OS 2). This is of course only performed if the floating point
- emulator is loaded. These functions are not intended to be used
- directly from C, but rather through an OS library’s Wimp interface
- (where they can be used as a drop-in replacement for the actual SWIs
- Wimp_Poll and Wimp_PollIdle). Indeed, they cannot be used from C,
- since the V flag requires checking. Hence it is not declared in the
- header file.
-
-
- _dll_iob
- _dll_errno
- _dll_ctype
- _dll_hugeval
-
- These functions are for internal use only. They locate items of data
- within the client application’s Shared C Library data area. Do not
- use them in your own code, except through the macros defined in the
- replacement C Library headers.
-
-
-